home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 005 / turbcalc.arc / CALC.PAS < prev    next >
Pascal/Delphi Source File  |  1985-03-18  |  34KB  |  1,274 lines

  1. program MicroCalc;
  2.  
  3. {
  4.     MICROCALC DEMONSTRATION PROGRAM  Version 1.00A
  5.  
  6.   This program is hereby donated to the public domain
  7.   for non-commercial use only.  Dot commands are  for
  8.   the program lister: LISTT.PAS  (available with  our
  9.   TURBO TUTOR):    .PA, .CP20, etc...
  10.  
  11.   INSTRUCTIONS
  12.   1.  Compile this program using the TURBO.COM compiler.
  13.       If a memory overflow occurs, compile the program:
  14.       CALCMAIN.PAS which will include this program.
  15.  
  16.   2.  Exit the program by typing: /Q
  17.  
  18.  Here is a note to the compiler:                                     }
  19.  
  20. {$R-,U-,V-,X-,C-}
  21.  
  22. const
  23.   FXMax: Char  = 'G';  { Maximum number of columns in spread sheet   }
  24.   FYMax        = 21;   { Maximum number of lines in spread sheet     }
  25.  
  26. type
  27.   Anystring   = string[70];
  28.   SheetIndex  = 'A'..'G';
  29.   Attributes  = (Constant,Formula,Txt,OverWritten,Locked,Calculated);
  30.  
  31. { The spreadsheet is made out of Cells every Cell is defined as      }
  32. { the following record:}
  33.  
  34.   CellRec    = record
  35.     CellStatus: set of Attributes; { Status of cell (see type def.)  }
  36.     Contents:   String[70];        { Contains a formula or some text }
  37.     Value:      Real;              { Last calculated cell value      }
  38.     DEC,FW:     0..20;             { Decimals and Cell Whith         }
  39.   end;
  40.  
  41.   Cells      =  array[SheetIndex,1..FYMax] of CellRec;
  42.  
  43. const
  44.   XPOS: array[SheetIndex] of integer = (3,14,25,36,47,58,68);
  45.  
  46. var
  47.   Sheet:         Cells;             { Definition of the spread sheet }
  48.   FX:            SheetIndex;        { Culumn of current cell         }
  49.   FY:            Integer;           { Line of current cell           }
  50.   Ch:            Char;              { Last read character            }
  51.   MCFile:        file of CellRec;   { File to store sheets in        }
  52.   AutoCalc:      boolean;           { Recalculate after each entry?  }
  53.  
  54.  
  55.  { For easy reference the procedures and functions are grouped in mo-}
  56.  { dules called MC-MOD00 through MC-MOD05.                           }
  57.  
  58.  
  59.  {.PA}
  60. {*******************************************************************}
  61. {*  SOURCE CODE MODULE: MC-MOD00                                   *}
  62. {*  PURPOSE:            Micellaneous utilities and commands.        *}
  63. {*******************************************************************}
  64.  
  65.  
  66. procedure Msg(S: AnyString);
  67. begin
  68.   GotoXY(1,24);
  69.   ClrEol;
  70.   Write(S);
  71. end;
  72.  
  73. procedure Flash(X: integer; S: AnyString;  Blink: boolean);
  74. begin
  75.   HighVideo;
  76.   GotoXY(X,23);
  77.   Write(S);
  78.   if Blink then
  79.   begin
  80.     repeat
  81.       GotoXY(X,23);
  82.       Blink:=not Blink; if Blink then HighVideo else LowVideo;
  83.       Write(S);
  84.       Delay(175);
  85.     until KeyPressed;
  86.   end;
  87.   LowVideo;
  88. end;
  89.  
  90. procedure IBMCh(var Ch: Char);
  91. begin
  92.   case Ch of
  93.     'H': Ch:=^E;
  94.     'P': Ch:=^X;
  95.     'M': Ch:=^D;
  96.     'K': Ch:=^S;
  97.     'S': Ch:=#127;
  98.     'R': Ch:=^V;
  99.     'G',
  100.     'I',
  101.     'O',
  102.     'Q': Ch:=#00;
  103.   end;
  104. end;
  105.  
  106. procedure Auto;
  107. begin
  108.   AutoCalc:=not AutoCalc;
  109.   if AutoCalc then  Flash(60,'AutoCalc: ON ',false)
  110.   else Flash(60,'AutoCalc: OFF',false);
  111. end;
  112.  
  113.  
  114. {.PA}
  115. {*******************************************************************}
  116. {*  SOURCE CODE MODULE: MC-MOD01                                   *}
  117. {*  PURPOSE:            Display grid and initialize all cells      *}
  118. {*                      in the spread sheet.                       *}
  119. {*******************************************************************}
  120.  
  121.  
  122.  
  123. procedure Grid;
  124. var I: integer;
  125.     Count: Char;
  126. begin
  127.   HighVideo;
  128.   For Count:='A' to FXMax do
  129.   begin
  130.     GotoXY(XPos[Count],1);
  131.     Write(Count);
  132.   end;
  133.   GotoXY(1,2);
  134.   for I:=1 to FYMax do writeln(I:2);
  135.   LowVideo;
  136.   if AutoCalc then  Flash(60,'AutoCalc: ON' ,false)
  137.   else Flash(60,'AutoCalc: OFF',false);
  138.   Flash(33,'  Type / for Commands',false);
  139. end;
  140.  
  141.  
  142. procedure Init;
  143. var
  144.   I: SheetIndex;
  145.   J: Integer;
  146.   LastName: string[2];
  147. begin
  148.   for I:='A' to FXMAX do
  149.   begin
  150.     for J:=1 to FYMAX do
  151.     begin
  152.       with Sheet[I,J] do
  153.       begin
  154.         CellStatus:=[Txt];
  155.         Contents:='';
  156.         Value:=0;
  157.         DEC:=2;              { Default number of decimals        }
  158.         FW:=10;              { Default field width               }
  159.       end;
  160.     end;
  161.   end;
  162.   AutoCalc:=True;
  163.   FX:='A'; FY:=1;            { First field in upper left corner  }
  164. end;
  165.  
  166. procedure Clear;
  167. begin
  168.   HighVideo;
  169.   GotoXY(1,24); ClrEol;
  170.   Write('Clear this worksheet? (Y/N) ');
  171.   repeat Read(Kbd,Ch) until Upcase(Ch) in ['Y','N'];
  172.   Write(Upcase(Ch));
  173.   if UpCase(Ch)='Y' then
  174.   begin
  175.     ClrScr;
  176.     Init;
  177.     Grid;
  178.   end;
  179. end;
  180.  
  181.  
  182.  
  183. {.PA}
  184. {*******************************************************************}
  185. {*  SOURCE CODE MODULE: MC-MOD02                                   *}
  186. {*  PURPOSE:            Display values in cells and move between   *}
  187. {*                      cells in the spread sheet.                 *}
  188. {*******************************************************************}
  189.  
  190.  
  191. procedure FlashType;
  192. begin
  193.   with Sheet[FX,FY] do
  194.   begin
  195.     GotoXY(1,23);
  196.     Write(FX,FY:2,' ');
  197.     if Formula in CellStatus  then write('Formula:')  else
  198.     if Constant in CellStatus then Write('Numeric ') else
  199.     if Txt in CellStatus then Write('Text    ');
  200.     GotoXY(1,24); ClrEol;
  201.     if Formula in CellStatus then Write(Contents);
  202.   end;
  203. end;
  204.  
  205.  
  206. { The following procedures move between the Cells on the calc sheet.}
  207. { Each Cell has an associated record containing its X,Y coordinates }
  208. { and data. See the type definition for "Cell".                     }
  209.  
  210. procedure GotoCell(GX: SheetIndex; GY: integer);
  211. begin
  212.   with Sheet[GX,GY] do
  213.   begin
  214.     HighVideo;
  215.     GotoXY(XPos[GX],GY+1);
  216.     Write('           ');
  217.     GotoXY(XPos[GX],GY+1);
  218.     if Txt in CellStatus then Write(Contents)
  219.     else
  220.     begin
  221.       if DEC>=0 then Write(Value:FW:DEC)
  222.       else Write(Value:FW);
  223.     end;
  224.     FlashType;
  225.     GotoXY(XPos[GX],GY+1);
  226.   end;
  227.   LowVideo;
  228. end;
  229.  
  230. {.CP20}
  231.  
  232. procedure LeaveCell(FX:SheetIndex;FY: integer);
  233. begin
  234.   with Sheet[FX,FY] do
  235.   begin
  236.     GotoXY(XPos[FX],FY+1);
  237.     LowVideo;
  238.     if Txt in CellStatus then Write(Contents)
  239.     else
  240.     begin
  241.       if DEC>=0 then Write(Value:FW:DEC)
  242.       else Write(Value:FW);
  243.     end;
  244.   end;
  245. end;
  246.  
  247.  
  248. {.CP20}
  249.  
  250. procedure Update;
  251. var
  252.   UFX: SheetIndex;
  253.   UFY: integer;
  254. begin
  255.   ClrScr;
  256.   Grid;
  257.   for UFX:='A' to FXMax do for UFY:=1 to FYMax do
  258.   if Sheet[UFX,UFY].Contents<>'' then LeaveCell(UFX,UFY);
  259.   GotoCell(FX,FY);
  260. end;
  261.  
  262. {.CP20}
  263.  
  264. procedure MoveDown;
  265. var Start: integer;
  266. begin
  267.   LeaveCell(FX,FY);
  268.   Start:=FY;
  269.   repeat
  270.     FY:=FY+1;
  271.     if FY>FYMax then FY:=1;
  272.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FY=Start);
  273.   if FY<>Start then GotoCell(FX,FY);
  274. end;
  275.  
  276. {.CP20}
  277.  
  278. procedure MoveUp;
  279. var Start: integer;
  280. begin
  281.   LeaveCell(FX,FY);
  282.   Start:=FY;
  283.   repeat
  284.     FY:=FY-1;
  285.     if FY<1 then FY:=FYMax;
  286.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FY=Start);
  287.   if FY<>Start then GotoCell(FX,FY);
  288. end;
  289.  
  290. {.CP20}
  291.  
  292. procedure MoveRight;
  293. var Start: SheetIndex;
  294. begin
  295.   LeaveCell(FX,FY);
  296.   Start:=FX;
  297.   repeat
  298.     FX:=Succ(FX);
  299.     if FX>FXMax then
  300.     begin
  301.       FX:='A';
  302.       FY:=FY+1;
  303.       if FY>FYMax then FY:=1;
  304.     end;
  305.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FX=Start);
  306.   if FX<>Start then GotoCell(FX,FY);
  307. end;
  308.  
  309. {.CP20}
  310.  
  311. procedure MoveLeft;
  312. var Start: SheetIndex;
  313. begin
  314.   LeaveCell(FX,FY);
  315.   Start:=FX;
  316.   repeat
  317.     FX:=Pred(FX);
  318.     if FX<'A' then
  319.     begin
  320.       FX:=FXMax;
  321.       FY:=FY-1;
  322.       if FY<1 then FY:=FYMax;
  323.     end;
  324.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FX=Start);
  325.   if FX<>Start then GotoCell(FX,FY);
  326. end;
  327.  
  328.  
  329. {.PA}
  330. {*******************************************************************}
  331. {*  SOURCE CODE MODULE: MC-MOD03                                   *}
  332. {*  PURPOSE:            Read, Save and Print a spread sheet.       *}
  333. {*                      Display on-line manual.                    *}
  334. {*******************************************************************}
  335.  
  336. type
  337.   String3 = string[3];
  338.  
  339. var
  340.   FileName: string[14];
  341.   Line: string[100];
  342.  
  343. function Exist(FileN: AnyString): boolean;
  344. var F: file;
  345. begin
  346.    {$I-}
  347.    assign(F,FileN);
  348.    reset(F);
  349.    {$I+}
  350.    if IOResult<>0 then Exist:=false
  351.    else
  352.    begin
  353.      Exist:=true;
  354.      close(F);
  355.    end;
  356. end;
  357.  
  358.  
  359. procedure GetFileName(var Line: AnyString; FileType:String3);
  360. begin
  361.   Line:='';
  362.   repeat
  363.     Read(Kbd,Ch);
  364.     if Upcase(Ch) in ['A'..'Z',^M] then
  365.     begin
  366.       write(Upcase(Ch));
  367.       Line:=Line+Ch;
  368.     end;
  369.   until (Ch=^M) or (length(Line)=8);
  370.   if Ch=^M then Delete(Line,Length(Line),1);
  371.   if Line<>'' then Line:=Line+'.'+FileType;
  372. end;
  373.  
  374. {.CP20}
  375.  
  376. procedure Save;
  377. var I: SheetIndex;
  378. J: integer;
  379. begin
  380.   HighVideo;
  381.   Msg('Save: Enter filename  ');
  382.   GetFileName(Filename,'MCS');
  383.   if FileName<>'' then
  384.   begin
  385.     Assign(MCFile,FileName);
  386.     Rewrite(MCFile);
  387.     for I:='A' to FXmax do
  388.     begin
  389.       for J:=1 to FYmax do
  390.       write(MCfile,Sheet[I,J]);
  391.     end;
  392.     Grid;
  393.     Close(MCFile);
  394.     LowVideo;
  395.     GotoCell(FX,FY);
  396.   end;
  397. end;
  398.  
  399. {.CP30}
  400.  
  401. procedure Load;
  402. begin
  403.   HighVideo;
  404.   Msg('Load: Enter filename  ');
  405.   GetFileName(Filename,'MCS');
  406.   if (Filename<>'') then if (not exist(FileName)) then
  407.   repeat
  408.     Msg('File not Found: Enter another filename  ');
  409.     GetFileName(Filename,'MCS');
  410.   until exist(FileName) or (FileName='');
  411.   if FileName<>'' then
  412.   begin
  413.     ClrScr;
  414.     Msg('Please Wait. Loading definition...');
  415.     Assign(MCFile,FileName);
  416.     Reset(MCFile);
  417.     for FX:='A' to FXmax do
  418.      for FY:=1 to FYmax do read(MCFile,Sheet[FX,FY]);
  419.     FX:='A'; FY:=1;
  420.     LowVideo;
  421.     UpDate;
  422.   end;
  423.   GotoCell(FX,FY);
  424. end;
  425.  
  426.  
  427. {.PA}
  428.  
  429. procedure Print;
  430. var
  431.   I:      SheetIndex;
  432.   J,Count,
  433.   LeftMargin: Integer;
  434.   P:          string[20];
  435.   MCFile:     Text;
  436. begin
  437.   HighVideo;
  438.   Msg('Print: Enter filename "P" for Printer> ');
  439.   GetFileName(Filename,'LST');
  440.   Msg('Left margin > ');  Read(LeftMargin);
  441.   if FileName='P.LST' then FileName:='Printer';
  442.   Msg('Printing to: ' + FileName + '....');
  443.   Assign(MCFile,FileName);
  444.   Rewrite(MCFile);
  445.   For Count:=1 to 5 do Writeln(MCFile);
  446.   for J:=1 to FYmax do
  447.   begin
  448.     Line:='';
  449.     for I:='A' to FXmax do
  450.     begin
  451.       with Sheet[I,J] do
  452.       begin
  453.         while (Length(Line)<XPOS[I]-4) do Line:=Line+' ';
  454.         if (Constant in CellStatus) or (Formula in CellStatus) then
  455.         begin
  456.           if not (Locked in CellStatus) then
  457.           begin
  458.             if DEC>0 then Str(Value:FW:DEC,P) else Str(Value:FW,P);
  459.             Line:=Line+P;
  460.           end;
  461.         end else Line:=Line+Contents;
  462.       end; { With }
  463.     end; { One line }
  464.     For Count:=1 to LeftMargin do Write(MCFile,' ');
  465.     writeln(MCFile,Line);
  466.   end; { End Column }
  467.   Grid;
  468.   Close(MCFile);
  469.   LowVideo;
  470.   GotoCell(FX,FY);
  471. end;
  472.  
  473. {.PA}
  474.  
  475. procedure Help;
  476. var
  477.   H: text;
  478.   Line: string[80];
  479.   J: integer;
  480.   Bold: boolean;
  481.  
  482. begin
  483.   if Exist('CALC.HLP') then
  484.   begin
  485.     Assign(H,'CALC.HLP');
  486.     Reset(H);
  487.     while not Eof(H) do
  488.     begin
  489.       ClrScr; Bold:=false; LowVideo;
  490.       Readln(H,Line);
  491.       repeat
  492.         Write('     ');
  493.         For J:=1 to Length(Line) do
  494.         begin
  495.           if Line[J]=^B then
  496.           begin
  497.             Bold:=not Bold;
  498.             if Bold then HighVideo else LowVideo;
  499.           end else write(Line[J]);
  500.         end;
  501.         Writeln;
  502.         Readln(H,Line);
  503.       until  Eof(H) or (Copy(Line,1,3)='.PA');
  504.       GotoXY(26,24); HighVideo;
  505.       write('<<< Please press any key to continue >>>');
  506.       LowVideo;
  507.       read(Kbd,Ch);
  508.     end;
  509.     GotoXY(20,24); HighVideo;
  510.     write('<<< Please press <RETURN> to start MicroCalc >>>');
  511.     LowVideo;
  512.     Readln(Ch);
  513.     UpDate;
  514.   end else { Help file did not exist }
  515.   begin
  516.     Msg('To get help the file CALC.HLP must be on your disk. Press <RETURN>');
  517.     repeat Read(kbd,Ch) until Ch=^M;
  518.     GotoCell(FX,FY);
  519.   end;
  520. end;
  521.  
  522.  
  523. {.PA}
  524. {*******************************************************************}
  525. {*  SOURCE CODE MODULE: MC-MOD04                                   *}
  526. {*  PURPOSE:            Evaluate formulas.                         *}
  527. {*                      Recalculate spread sheet.                  *}
  528. {*                                                                 *}
  529. {*  NOTE:               This module contains recursive procedures  *}
  530. {*******************************************************************}
  531.  
  532. var
  533.   Form: Boolean;
  534.  
  535. {$A-}
  536. procedure Evaluate(var IsFormula: Boolean; { True if formula}
  537.                    var Formula: AnyString; { Fomula to evaluate}
  538.                    var Value: Real;  { Result of formula }
  539.                    var ErrPos: Integer);{ Position of error }
  540. const
  541.   Numbers: set of Char = ['0'..'9'];
  542.   EofLine  = ^M;
  543.  
  544. var
  545.   Pos: Integer;    { Current position in formula                     }
  546.   Ch: Char;        { Current character being scanned                 }
  547.   EXY: string[3];  { Intermidiate string for conversion              }
  548.  
  549. { Procedure NextCh returns the next character in the formula         }
  550. { The variable Pos contains the position ann Ch the character        }
  551.  
  552.   procedure NextCh;
  553.   begin
  554.     repeat
  555.       Pos:=Pos+1;
  556.       if Pos<=Length(Formula) then
  557.       Ch:=Formula[Pos] else Ch:=eofline;
  558.     until Ch<>' ';
  559.   end  { NextCh };
  560.  
  561.  
  562.   function Expression: Real;
  563.   var
  564.     E: Real;
  565.     Opr: Char;
  566.  
  567.     function SimpleExpression: Real;
  568.     var
  569.       S: Real;
  570.       Opr: Char;
  571.  
  572.       function Term: Real;
  573.       var
  574.         T: Real;
  575.  
  576.         function SignedFactor: Real;
  577.  
  578.           function Factor: Real;
  579.           type
  580.             StandardFunction = (fabs,fsqrt,fsqr,fsin,fcos,
  581.             farctan,fln,flog,fexp,ffact);
  582.             StandardFunctionList = array[StandardFunction] of string[6];
  583.  
  584.           const
  585.             StandardFunctionNames: StandardFunctionList =('ABS','SQRT','SQR','SIN','COS',
  586.                                                           'ARCTAN','LN','LOG','EXP','FACT');
  587.           var
  588.             E,EE,L:  Integer;       { intermidiate variables }
  589.             Found:Boolean;
  590.             F: Real;
  591.             Sf:StandardFunction;
  592.             OldEFY,                 { Current cell  }
  593.             EFY,
  594.             SumFY,
  595.             Start:Integer;
  596.             OldEFX,
  597.             EFX,
  598.             SumFX:SheetIndex;
  599.             CellSum: Real;
  600.  
  601.               function Fact(I: Integer): Real;
  602.               begin
  603.                 if I > 0 then begin Fact:=I*Fact(I-1); end
  604.                 else Fact:=1;
  605.               end  { Fact };
  606.  
  607. {.PA}
  608.           begin { Function Factor }
  609.             if Ch in Numbers then
  610.             begin
  611.               Start:=Pos;
  612.               repeat NextCh until not (Ch in Numbers);
  613.               if Ch='.' then repeat NextCh until not (Ch in Numbers);
  614.               if Ch='E' then
  615.               begin
  616.                 NextCh;
  617.                 repeat NextCh until not (Ch in Numbers);
  618.               end;
  619.               Val(Copy(Formula,Start,Pos-Start),F,ErrPos);
  620.             end else
  621.             if Ch='(' then
  622.             begin
  623.               NextCh;
  624.               F:=Expression;
  625.               if Ch=')' then NextCh else ErrPos:=Pos;
  626.             end else
  627.             if Ch in ['A'..'G'] then { Maybe a cell reference }
  628.             begin
  629.               EFX:=Ch;
  630.               NextCh;
  631.               if Ch in Numbers then
  632.               begin
  633.                 F:=0;
  634.                 EXY:=Ch; NextCh;
  635.                 if Ch in Numbers then
  636.                 begin
  637.                   EXY:=EXY+Ch;
  638.                   NextCh;
  639.                 end;
  640.                 Val(EXY,EFY,ErrPos);
  641.                 IsFormula:=true;
  642.                 if (Constant in Sheet[EFX,EFY].CellStatus) and
  643.                 not (Calculated in Sheet[EFX,EFY].CellStatus) then
  644.                 begin
  645.                   Evaluate(Form,Sheet[EFX,EFY].contents,f,ErrPos);
  646.                   Sheet[EFX,EFY].CellStatus:=Sheet[EFX,EFY].CellStatus+[Calculated]
  647.                 end else if not (Txt in Sheet[EFX,EFY].CellStatus) then
  648.                 F:=Sheet[EFX,EFY].Value;
  649.                 if Ch='>' then
  650.                 begin
  651.                   OldEFX:=EFX; OldEFY:=EFY;
  652.                   NextCh;
  653.                   EFX:=Ch;
  654.                   NextCh;
  655.                   if Ch in Numbers then
  656.                   begin
  657.                     EXY:=Ch;
  658.                     NextCh;
  659.                     if Ch in Numbers then
  660.                     begin
  661.                       EXY:=EXY+Ch;
  662.                       NextCh;
  663.                     end;
  664.                     val(EXY,EFY,ErrPos);
  665.                     Cellsum:=0;
  666.                     for SumFY:=OldEFY to EFY do
  667.                     begin
  668.                       for SumFX:=OldEFX to EFX do
  669.                       begin
  670.                         F:=0;
  671.                         if (Constant in Sheet[SumFX,SumFY].CellStatus) and
  672.                         not (Calculated in Sheet[SumFX,SumFY].CellStatus) then
  673.                         begin
  674.                           Evaluate(Form,Sheet[SumFX,SumFY].contents,f,errPos);
  675.                           Sheet[SumFX,SumFY].CellStatus:=
  676.                           Sheet[SumFX,SumFY].CellStatus+[Calculated];
  677.                         end else if not (Txt in Sheet[SumFX,SumFY].CellStatus) then
  678.                         F:=Sheet[SumFX,SumFY].Value;
  679.                         Cellsum:=Cellsum+f;
  680.                         f:=Cellsum;
  681.                       end;
  682.                     end;
  683.                   end;
  684.                 end;
  685.               end;
  686.             end else
  687.             begin
  688.               found:=false;
  689.               for sf:=fabs to ffact do
  690.               if not found then
  691.               begin
  692.                 l:=Length(StandardFunctionNames[sf]);
  693.                 if copy(Formula,Pos,l)=StandardFunctionNames[sf] then
  694.                 begin
  695.                   Pos:=Pos+l-1; NextCh;
  696.                   F:=Factor;
  697.                   case sf of
  698.                     fabs:     f:=abs(f);
  699.                     fsqrt:    f:=sqrt(f);
  700.                     fsqr:     f:=sqr(f);
  701.                     fsin:     f:=sin(f);
  702.                     fcos:     f:=cos(f);
  703.                     farctan:  f:=arctan(f);
  704.                     fln :     f:=ln(f);
  705.                     flog:     f:=ln(f)/ln(10);
  706.                     fexp:     f:=exp(f);
  707.                     ffact:    f:=fact(trunc(f));
  708.                   end;
  709.                   Found:=true;
  710.                 end;
  711.               end;
  712.               if not Found then ErrPos:=Pos;
  713.             end;
  714.             Factor:=F;
  715.           end { function Factor};
  716. {.PA}
  717.  
  718.         begin { SignedFactor }
  719.           if Ch='-' then
  720.           begin
  721.             NextCh; SignedFactor:=-Factor;
  722.           end else SignedFactor:=Factor;
  723.         end { SignedFactor };
  724.  
  725.       begin { Term }
  726.         T:=SignedFactor;
  727.         while Ch='^' do
  728.         begin
  729.           NextCh; t:=exp(ln(t)*SignedFactor);
  730.         end;
  731.         Term:=t;
  732.       end { Term };
  733.  
  734.  
  735.     begin { SimpleExpression }
  736.       s:=term;
  737.       while Ch in ['*','/'] do
  738.       begin
  739.         Opr:=Ch; NextCh;
  740.         case Opr of
  741.           '*': s:=s*term;
  742.           '/': s:=s/term;
  743.         end;
  744.       end;
  745.       SimpleExpression:=s;
  746.     end { SimpleExpression };
  747.  
  748.   begin { Expression }
  749.     E:=SimpleExpression;
  750.     while Ch in ['+','-'] do
  751.     begin
  752.       Opr:=Ch; NextCh;
  753.       case Opr of
  754.         '+': e:=e+SimpleExpression;
  755.         '-': e:=e-SimpleExpression;
  756.       end;
  757.     end;
  758.     Expression:=E;
  759.   end { Expression };
  760.  
  761.  
  762. begin { procedure Evaluate }
  763.   if Formula[1]='.' then Formula:='0'+Formula;
  764.   if Formula[1]='+' then delete(Formula,1,1);
  765.   IsFormula:=false;
  766.   Pos:=0; NextCh;
  767.   Value:=Expression;
  768.   if Ch=EofLine then ErrPos:=0 else ErrPos:=Pos;
  769. end { Evaluate };
  770.  
  771. {.PA}
  772.  
  773. procedure Recalculate;
  774. var
  775.   RFX: SheetIndex;
  776.   RFY:integer;
  777.   OldValue: real;
  778.   Err: integer;
  779.  
  780. begin
  781.   LowVideo;
  782.   GotoXY(1,24); ClrEol;
  783.   Write('Calculating..');
  784.   for RFY:=1 to FYMax do
  785.   begin
  786.     for RFX:='A' to FXMax do
  787.     begin
  788.       with Sheet[RFX,RFY] do
  789.       begin
  790.         if (Formula in CellStatus) then
  791.         begin
  792.           CellStatus:=CellStatus+[Calculated];
  793.           OldValue:=Value;
  794.           Evaluate(Form,Contents,Value,Err);
  795.           if OldValue<>Value then
  796.           begin
  797.             GotoXY(XPos[RFX],RFY+1);
  798.             if (DEC>=0) then Write(Value:FW:DEC)
  799.             else Write(Value:FW);
  800.           end;
  801.         end;
  802.       end;
  803.     end;
  804.   end;
  805.   GotoCell(FX,FY);
  806. end;
  807.  
  808. {.PA}
  809. {*******************************************************************}
  810. {*  SOURCE CODE MODULE: MC-MOD05                                   *}
  811. {*  PURPOSE:            Read the contents of a cell and update     *}
  812. {*                      associated cells.                          *}
  813. {*******************************************************************}
  814.  
  815.  
  816. procedure GetLine(var S: AnyString;           { String to edit       }
  817.                          ColNO,LineNO,        { Where start line     }
  818.                          MAX,                 { Max length           }
  819.                          ErrPos: integer;     { Where to begin       }
  820.                          UpperCase:Boolean);  { True if auto Upcase  }
  821. var
  822.   X: integer;
  823.   InsertOn: boolean;
  824.   OkChars: set of Char;
  825.  
  826.  
  827.   procedure GotoX;
  828.   begin
  829.     GotoXY(X+ColNo-1,LineNo);
  830.   end;
  831.  
  832. begin
  833.   OkChars:=[' '..'}'];
  834.   InsertOn:=true;
  835.   X:=1; GotoX;
  836.   Write(S);
  837.   if Length(S)=1 then X:=2;
  838.   if ErrPos<>0 then X:=ErrPos;
  839.   GotoX;
  840.   repeat
  841.     Read(Kbd,Ch);
  842.     if KeyPressed then
  843.     begin
  844.       Read(kbd,Ch);
  845.       IBMCh(Ch);
  846.     end;
  847.     if UpperCase then Ch:=UpCase(Ch);
  848.     case Ch of
  849.        ^[: begin
  850.              S:=chr($FF); { abort editing }
  851.              Ch:=^M;
  852.            end;
  853.        ^D: begin { Move cursor right }
  854.              X:=X+1;
  855.              if (X>length(S)+1) or (X>MAX) then X:=X-1;
  856.              GotoX;
  857.            end;
  858.        ^G: begin { Delete right char }
  859.              if X<=Length(S) then
  860.              begin
  861.                Delete(S,X,1);
  862.                Write(copy(S,X,Length(S)-X+1),' ');
  863.                GotoX;
  864.              end;
  865.            end;
  866.     ^S,^H: begin { Move cursor left }
  867.              X:=X-1;
  868.              if X<1 then X:=1;
  869.              GotoX;
  870.            end;
  871.        ^F: begin { Move cursor to end of line }
  872.               X:=Length(S)+1;
  873.               GotoX;
  874.            end;
  875.        ^A: begin { Move cursor to beginning of line }
  876.              X:=1;
  877.              GotoX;
  878.            end;
  879.      #127: begin { Delete left char }
  880.              X:=X-1;
  881.              if (Length(S)>0) and (X>0)  then
  882.              begin
  883.                Delete(S,X,1);
  884.                Write(copy(S,X,Length(S)-X+1),' ');
  885.                GotoX;
  886.                if X<1 then X:=1;
  887.              end else X:=1;
  888.            end;
  889.        ^V: InsertOn:= not InsertOn;
  890.  
  891. {.PA}
  892.  
  893.     else
  894.       begin
  895.         if Ch in OkChars  then
  896.         begin
  897.           if InsertOn then
  898.           begin
  899.             insert(Ch,S,X);
  900.             Write(copy(S,X,Length(S)-X+1),' ');
  901.           end else
  902.           begin
  903.             write(Ch);
  904.             if X=length(S) then S:=S+Ch
  905.               else S[X]:=Ch;
  906.           end;
  907.           if Length(S)+1<=MAX then X:=X+1
  908.           else OkChars:=[]; { Line too Long }
  909.           GotoX;
  910.         end else
  911.         if Length(S)+1<=Max then
  912.           OkChars:= [' '..'}']; { Line ok again }
  913.       end;
  914.     end;
  915.   until CH=^M;
  916. end;
  917.  
  918.  
  919. {.PA}
  920.  
  921.  
  922. procedure  GetCell(FX: SheetIndex;FY: Integer);
  923. var
  924.   S:             AnyString;
  925.   NewStat:       Set of Attributes;
  926.   ErrorPosition: Integer;
  927.   I:             SheetIndex;
  928.   Result:        Real;
  929.   Abort:         Boolean;
  930.   IsForm:        Boolean;
  931.  
  932. { Procedure ClearCells clears the current cell and its associated    }
  933. { cells. An associated cell is a cell overwritten by data from the   }
  934. { current cell. The data can be text in which case the cell has the  }
  935. { attribute "OverWritten". If the data is a result from an expression}
  936. { and the field with is larger tahn 11 then the cell is "Locked"     }
  937.  
  938.   procedure ClearCells;
  939.   begin
  940.     I:=FX;
  941.     repeat
  942.       with Sheet[I,FY] do
  943.       begin
  944.         GotoXY(XPos[I],FY+1);
  945.         write('           '); I:=Succ(I);
  946.       end;
  947.     until ([OverWritten,Locked]*Sheet[I,FY].CellStatus=[]);
  948.     { Cell is not OVerWritten not Locked }
  949.   end;
  950.  
  951. {.CP20}
  952. { The new type of the cell is flashed at the bottom of the Sheet     }
  953. { Notice that a constant of type array is used to indicate the type  }
  954.  
  955.   procedure FlashType;
  956.   begin
  957.     HighVideo;
  958.     GotoXY(5,23);
  959.     LowVideo;
  960.   end;
  961.  
  962. {.CP20}
  963.   procedure GetFormula;
  964.   begin
  965.     FlashType;
  966.     repeat
  967.       GetLine(S,1,24,70,ErrorPosition,True);
  968.       if S<>Chr($FF) then
  969.       begin
  970.         Evaluate(IsForm,S,Result,ErrorPosition);
  971.         if ErrorPosition<>0 then
  972.           Flash(15,'Error at cursor'+^G,false)
  973.         else Flash(15,'               ',false);
  974.       end;
  975.     until (ErrorPosition=0) or (S=Chr($FF));
  976.     if IsForm then NewStat:=NewStat+[Formula];
  977.   end;
  978.  
  979. {.CP20}
  980. { Procedure GetText calls the procedure GetLine with the current     }
  981. { cells X,Y position as parameters. This means that text entering    }
  982. { takes place direcly at the cells position on the Sheet.            }
  983.  
  984.   procedure GetText;
  985.   begin
  986.     FlashType;
  987.     with Sheet[FX,FY] do GetLine(S,XPos[FX],FY+1,70,ErrorPosition,False);
  988.   end;
  989.  
  990. {.CP20}
  991. { Procedure EditCell loads a copy of the current cells contents in   }
  992. { in the variable S before calling either GetText or GetFormula. In  }
  993. { this way no changes are made to the current cell.                  }
  994.  
  995.   procedure EditCell;
  996.   begin
  997.     with Sheet[FX,FY] do
  998.     begin
  999.       S:=Contents;
  1000.       if Txt in CellStatus then GetText else GetFormula;
  1001.     end;
  1002.   end;
  1003.  
  1004. {.PA}
  1005. { Procedure UpdateCells is a little more complicated. Basically it   }
  1006. { makes sure to tag and untag cells which has been overwritten or    }
  1007. { cleared from data from  another cell. It also updates the current  }
  1008. { with the new type and the contents which still is in the temporaly }
  1009. { variable "S".                                                      }
  1010.  
  1011.  
  1012.   procedure UpdateCells;
  1013.   var
  1014.     Flength: Integer;
  1015.   begin
  1016.     Sheet[FX,FY].Contents:=S;
  1017.     if Txt in NewStat {Sheet[FX,FY].CellStatus} then
  1018.     begin
  1019.       I:=FX; FLength:=Length(S);
  1020.       repeat
  1021.         I:=Succ(I);
  1022.         with Sheet[I,FY] do
  1023.         begin
  1024.           FLength:=Flength-11;
  1025.           if (Flength>0) then
  1026.           begin
  1027.             CellStatus:=[Overwritten,Txt];
  1028.             Contents:='';
  1029.           end else
  1030.           begin
  1031.             if OverWritten in CellStatus then
  1032.             begin
  1033.               CellStatus:=[Txt];
  1034.               GotoCell(I,FY);LeaveCell(I,FY);
  1035.             end;
  1036.           end;
  1037.         end;
  1038.       until (I=FXMax)  or (Sheet[I,FY].Contents<>'');
  1039.       Sheet[FX,FY].CellStatus:=[Txt];
  1040.     end else { string changed to formula or constant }
  1041.     begin { Event number two }
  1042.       I:=FX;
  1043.       repeat
  1044.         with Sheet[I,FY] do
  1045.         begin
  1046.           if OverWritten in CellStatus then
  1047.           begin
  1048.             CellStatus:=[Txt];
  1049.             Contents:='';
  1050.           end;
  1051.           I:=Succ(I);
  1052.         end;
  1053.       until not (OverWritten in Sheet[I,FY].CellStatus);
  1054.       with Sheet[FX,FY] do
  1055.       begin
  1056.         CellStatus:=[Constant];
  1057.         if IsForm then CellStatus:=CellStatus+[Formula];
  1058.         Value:=Result;
  1059.       end;
  1060.     end;
  1061.   end;
  1062.  
  1063.  
  1064. {.PA}
  1065. { Procedure GetCell finnaly starts here. This procedure uses all     }
  1066. { all the above local procedures. First it initializes the temporaly }
  1067. { variable "S" with the last read character. It then depending on    }
  1068. { this character calls GetFormula, GetText, or EditCell.             }
  1069.  
  1070. begin { procedure GetCell }
  1071.   S:=Ch; ErrorPosition:=0; Abort:=false;
  1072.   NewStat:=[];
  1073.   if Ch in ['0'..'9','+','-','.','(',')'] then
  1074.   begin
  1075.     NewStat:=[Constant];
  1076.     if not (Formula in Sheet[FX,FY].CellStatus) then
  1077.     begin
  1078.       GotoXY(11,24); ClrEol;
  1079.       ClearCells;
  1080.       GetFormula;
  1081.     end else
  1082.     begin
  1083.       Flash(15,'Edit formula Y/N?',true);
  1084.       repeat read(Kbd,Ch) until UpCase(CH) in ['Y','N'];
  1085.       Flash(15,'                 ',false);
  1086.       if UpCase(Ch)='Y' then EditCell Else Abort:=true;
  1087.     end;
  1088.   end else
  1089.   begin
  1090.     if Ch=^[ then
  1091.     begin
  1092.       NewStat:=(Sheet[FX,FY].CellStatus)*[Txt,Constant];
  1093.       EditCell;
  1094.     end else
  1095.     begin
  1096.       if formula in Sheet[FX,FY].CellStatus then
  1097.       begin
  1098.         Flash(15,'Edit formula Y/N?',true);
  1099.         repeat read(Kbd,Ch) until UpCase(CH) in ['Y','N'];
  1100.         Flash(15,'                 ',false);
  1101.         if UpCase(Ch)='Y' then EditCell Else Abort:=true;
  1102.       end else
  1103.       begin
  1104.         NewStat:=[Txt];
  1105.         ClearCells;
  1106.         GetText;
  1107.       end;
  1108.     end;
  1109.   end;
  1110.   if not Abort then
  1111.   begin
  1112.     if S<>Chr($FF) then UpDateCells;
  1113.     GotoCell(FX,FY);
  1114.     if AutoCalc and (Constant in Sheet[FX,FY].CellStatus) then Recalculate;
  1115.     if Txt in NewStat then
  1116.     begin
  1117.       GotoXY(3,FY+1); Clreol;
  1118.       For I:='A' to FXMax do
  1119.       LeaveCell(I,FY);
  1120.     end;
  1121.   end;
  1122.   Flash(15,'                ',False);
  1123.   GotoCell(FX,FY);
  1124. end;
  1125.  
  1126. {.PA}
  1127. { Procedure Format is used to }
  1128.  
  1129.  
  1130. procedure Format;
  1131. var
  1132.   J,FW,DEC,
  1133.   FromLine,ToLine: integer;
  1134.   Lock:            Boolean;
  1135.  
  1136.  
  1137.   procedure GetInt(var I: integer; Max: Integer);
  1138.   var
  1139.     S: string[8];
  1140.     Err: Integer;
  1141.     Ch: Char;
  1142.   begin
  1143.     S:='';
  1144.     repeat
  1145.       repeat Read(Kbd,Ch) until Ch in ['0'..'9','-',^M];
  1146.       if Ch<>^M then
  1147.       begin
  1148.         Write(Ch); S:=S+Ch;
  1149.         Val(S,I,Err);
  1150.       end;
  1151.     until (I>=Max) or (Ch=^M);
  1152.     if I>Max then I:=Max;
  1153.   end;
  1154.  
  1155. begin
  1156.   HighVideo;
  1157.   Msg('Format: Enter number of decimals (Max 11):  ');
  1158.   GetInt(DEC,11);
  1159.   Msg('Enter Cell whith remember if larger than 10 next column will lock: ');
  1160.   GetInt(FW,20);
  1161.   Msg('From which line in column '+FX+': ');
  1162.   GetInt(FromLine,FYMax);
  1163.   Msg('To which line in column '+FX+': ');
  1164.   GetInt(ToLine,FYMax);
  1165.   if FW>10 then Lock:=true else Lock:=False;
  1166.   for J:=FromLine to ToLine do
  1167.   begin
  1168.     Sheet[FX,J].DEC:=DEC;
  1169.     Sheet[FX,J].FW:=FW;
  1170.     with Sheet[Succ(FX),J] do
  1171.     begin
  1172.       if Lock then
  1173.       begin
  1174.         CellStatus:=CellStatus+[Locked,Txt];
  1175.         Contents:='';
  1176.       end else CellStatus:=CellStatus-[Locked];
  1177.     end;
  1178.   end;
  1179.   NormVideo;
  1180.   UpDate;
  1181.   GotoCell(FX,FY);
  1182. end;
  1183.  
  1184.  
  1185. {.PA}
  1186. {*********************************************************************}
  1187. {*                START OF MAIN PROGRAM PROCEDURES                   *}
  1188. {*********************************************************************}
  1189.  
  1190.  
  1191. { Procedure Commands is activated from the main loop in this program }
  1192. { when the user types a slash (/). a procedure activates a procedure}
  1193. { which will execute the command. These procedures are located in the}
  1194. { above modules.                                                     }
  1195.  
  1196. { For easy reference the source code module number is shown in a     }
  1197. { comment on the right following the procedure call.                 }
  1198.  
  1199. procedure Commands;
  1200. begin
  1201.   GotoXY(1,24);
  1202.   HighVideo;
  1203.   Write('/ restore Quit, Load, Save, Recalculate, Print, Format, AutoCalc, Help ');
  1204.   Read(Kbd,Ch);
  1205.   Ch:=UpCase(Ch);
  1206.   case Ch of                                             { In module }
  1207.     'Q': Halt;
  1208.     'F': Format;                                               {  04 }
  1209.     'S': Save;                                                 {  03 }
  1210.     'L': Load;                                                 {  03 }
  1211.     'H': Help;                                                 {  03 }
  1212.     'R': Recalculate;                                          {  05 }
  1213.     'A': Auto;                                                 {  00 }
  1214.     '/': Update;                                               {  01 }
  1215.     'C': Clear;                                                {  01 }
  1216.     'P': Print;                                                {  03 }
  1217.   end;
  1218.   Grid;                                                        {  01 }
  1219.   GotoCell(FX,FY);                                             {  02 }
  1220. end;
  1221.  
  1222. { Procedure Hello says hello and activates the help procedure if the }
  1223. { user presses anything but Return                                   }
  1224.  
  1225. procedure Welcome;
  1226.  
  1227.   procedure Center(S: AnyString);
  1228.   var I: integer;
  1229.   begin
  1230.     for I:=1 to (80-Length(S)) div 2 do Write(' ');
  1231.     writeln(S);
  1232.   end;
  1233.  
  1234. begin { procedure Wellcome }
  1235.   ClrScr; GotoXY(1,9);
  1236.   Center('Welcome to MicroCalc.  A Turbo demonstation program');
  1237.   Center('Press any key for help or <RETURN> to start');
  1238.   GotoXY(40,12);
  1239.   Read(Kbd,Ch);
  1240.   if Ch<>^M then Help;
  1241. end;
  1242.  
  1243. {.PA}
  1244. {*********************************************************************}
  1245. {*          THIS IS WHERE THE PROGRAM STARTS EXECUTING               *}
  1246. {*********************************************************************}
  1247.  
  1248. begin
  1249.   Init;                                                        {  01 }
  1250.   Welcome;
  1251.   ClrScr; Grid;                                                {  01 }
  1252.   GotoCell(FX,FY);
  1253.   repeat
  1254.     Read(Kbd,Ch);
  1255.     if KeyPressed then
  1256.     begin
  1257.       read(kbd,Ch);
  1258.       IBMCh(Ch);
  1259.     end;
  1260.     case Ch of
  1261.       ^E:       MoveUp;                                        {  02 }
  1262.       ^X,^J:    MoveDown;                                      {  02 }
  1263.       ^D,^M,^F: MoveRight;                                     {  02 }
  1264.       ^S,^A:    MoveLeft;                                      {  02 }
  1265.       '/':      Commands;
  1266.       ^[:       GetCell(FX,FY);                                {  04 }
  1267.     else
  1268.       if Ch in [' '..'~'] then
  1269.       GetCell(FX,FY);                                          {  04 }
  1270.     end;
  1271.   until true=false;          { (program stops in procedure Commands) }
  1272. end.
  1273.  
  1274.